
#ifndef __COMPILER_EXPRESSION_HPP__
#define __COMPILER_EXPRESSION_HPP__

#include <string>
#include <vector>
#include <map>
#include <climits>
#include <cassert>

#include "list.hpp"

typedef std::vector< unsigned int > IndexArray;

class Expression
{
public:

  Expression()
  : _type(),
    _name()
  {}

  Expression( const Expression& expression )
  : _type( expression.GetType() ),
    _name( expression.GetName() )
  {}

  bool IsTypeArithmetic() const
  {
    if( _type == "boolean" || _type == "integer" || _type == "character" )
      return true;
    else
      return false;
  }

  bool IsCompatibleWith( const Expression& expression ) const
  {
    return this->GetType() == expression.GetType();
  }

  void SetName( const std::string& name ) { _name = name; }
  void SetType( const std::string& type ) { _type = type; }
  const std::string& GetType() const { return _type; }
  const std::string& GetName() const { return _name; }

  void SetTrueList( const IndexArray& list ) { _trueList = list; }
  void SetFalseList( const IndexArray& list ) { _falseList = list; }
  void SetTrueList( const IndexArray& listA, const IndexArray& listB )
  {
    Merge( _trueList, listA, listB );
  }
  void SetFalseList( const IndexArray& listA, const IndexArray& listB )
  {
    Merge( _falseList, listA, listB );
  }

  void AppendFalseList( const IndexArray& list )
  {
    Merge( _falseList, _falseList, list );
  }

  void AppendTrueList( const IndexArray& list )
  {
    Merge( _trueList, _trueList, list );
  }

  void SwapLists() { _trueList.swap( _falseList ); }

  IndexArray& GetTrueList() {return _trueList;}
  IndexArray& GetFalseList() {return _falseList;}

  IndexArray _trueList;
  IndexArray _falseList;

private:

  std::string _type;
  std::string _name;
};

class UnaryExpression : public Expression
{
public:
  UnaryExpression( const Expression& op )
  : _op( op )
  {
    this->SetType( op.GetType() );
  }

private:

  Expression _op;
};


class BinaryExpression: public Expression
{

public:

  BinaryExpression( const Expression& opA, const Expression& opB )
  : Expression::Expression(),
    _opA( opA ),
    _opB( opB )
  {
    // Type verification
    assert( _opA.IsCompatibleWith( _opB ) );

    // Type synthesis is just get the same type as operands
    this->SetType( _opA.GetType() );
  }

protected:

  const Expression _opA, _opB;
};


class BooleanExpression : public BinaryExpression
{
public:
  BooleanExpression( const Expression& opA, const Expression& opB )
  : BinaryExpression::BinaryExpression( opA, opB )
  {
    // Type verification
    assert( _opA.IsTypeArithmetic() );

    this->SetType( "boolean" );
  }
};

class RelationalExpression : public BinaryExpression
{
public:
  RelationalExpression( const Expression& opA, const Expression& opB )
  : BinaryExpression::BinaryExpression( opA, opB )
  {
    // Type verification
    assert( _opA.IsTypeArithmetic() );
  }
};
class ArithmeticExpression : public BinaryExpression
{
public:
  ArithmeticExpression( const Expression& opA, const Expression& opB )
  : BinaryExpression::BinaryExpression( opA, opB )
  {
    // Type verification
    assert( _opA.IsTypeArithmetic() );
  }
};

#endif // __COMPILER_EXPRESSION_HPP__
